#include "stdafx.h"
#include <stddef.h>
#include "MyIExampleEvts.h"
#include "RealIExampleEvts.h"

ITypeInfo *ExampleEvtsTypeInfo;

HRESULT LoadExampleEvtsTypeInfo()
{
    HRESULT hr;
    ITypeLib *pTypeLib = NULL;
    hr = LoadRegTypeLib(TLBID_IExampleEvts, 1, 0, 0, &pTypeLib);
    if (FAILED(hr)) return hr;
    hr = pTypeLib->GetTypeInfoOfGuid(IID_IExampleEvts, &ExampleEvtsTypeInfo);
    pTypeLib->Release();
    if (FAILED(hr)) return hr;
    ExampleEvtsTypeInfo->AddRef();
    return S_OK;
}

RealIExampleEvts::RealIExampleEvts()
{
}

RealIExampleEvts::~RealIExampleEvts()
{
}

HRESULT STDMETHODCALLTYPE RealIExampleEvts::QueryInterface(REFIID riid, void **ppv)
{
    if (IsEqualIID(riid, IID_IUnknown) ||
        IsEqualIID(riid, IID_IDispatch) ||
        IsEqualIID(riid, IID_IExampleEvts))
    {
        *ppv = this;
    }
    else if (IsEqualIID(riid, IID_IConnectionPointContainer))
    {
        *ppv = (unsigned char *)this + offsetof(MyIExampleEvts, container);
    }
    else
    {
        *ppv = NULL;
        return E_NOINTERFACE;
    }

    AddRef();
    return S_OK;
}

ULONG STDMETHODCALLTYPE RealIExampleEvts::AddRef()
{
    MyIExampleEvts *p = (MyIExampleEvts *)this;
    return ++p->count;
}

ULONG STDMETHODCALLTYPE RealIExampleEvts::Release()
{
    MyIExampleEvts *p = (MyIExampleEvts *)this;
    if (--p->count == 0)
    {
        delete p;
        InterlockedDecrement(&OutstandingObjects);
        return 0;
    }
    return p->count;
}

HRESULT STDMETHODCALLTYPE RealIExampleEvts::GetTypeInfoCount(UINT *pctinfo)
{
    *pctinfo = 1;
    return S_OK;
}

HRESULT STDMETHODCALLTYPE RealIExampleEvts::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
{
    *ppTInfo = NULL;
    if (iTInfo != 0) return DISP_E_BADINDEX;
    if (ExampleEvtsTypeInfo != NULL)
    {
        ExampleEvtsTypeInfo->AddRef();
    }
    else
    {
        HRESULT hr = LoadExampleEvtsTypeInfo();
        if (FAILED(hr)) return hr;
    }
    *ppTInfo = ExampleEvtsTypeInfo;
    return S_OK;
}

HRESULT STDMETHODCALLTYPE RealIExampleEvts::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
{
    if (ExampleEvtsTypeInfo == NULL)
    {
        HRESULT hr = LoadExampleEvtsTypeInfo();
        if (FAILED(hr)) return hr;
    }
    return DispGetIDsOfNames(ExampleEvtsTypeInfo, rgszNames, cNames, rgDispId);
}

HRESULT STDMETHODCALLTYPE RealIExampleEvts::Invoke(DISPID dispIdMember, REFIID riid,
                                                   LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
                                                   VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
    if (!IsEqualIID(riid, IID_NULL)) return DISP_E_UNKNOWNINTERFACE;
    if (ExampleEvtsTypeInfo == NULL)
    {
        HRESULT hr = LoadExampleEvtsTypeInfo();
        if (FAILED(hr)) return hr;
    }
    return DispInvoke(this, ExampleEvtsTypeInfo, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
}

HRESULT STDMETHODCALLTYPE RealIExampleEvts::DoSomething()
{
    MyIExampleEvts *p = (MyIExampleEvts *)this;
    if (p->feedback == NULL) return E_FAIL;

    DISPPARAMS args;
    ZeroMemory(&args, sizeof(DISPPARAMS));
    for (int i = 1; i <= 3; ++i)
    {
        HRESULT hr = p->feedback->Invoke(i, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &args, NULL, NULL, NULL);
        if (FAILED(hr)) return hr;
    }
    return S_OK;
}

HRESULT STDMETHODCALLTYPE RealIExampleEvts::Sort(LPVOID base, DWORD numElems, DWORD sizeElem)
{
    MyIExampleEvts *p = (MyIExampleEvts *)this;
    if (p->compare == NULL) return E_FAIL;

    char *hi = (char *)base + (numElems - 1) * sizeElem;
    char *temp = new char[sizeElem];
    if (temp == NULL) return E_OUTOFMEMORY;

    VARIANT args[2];
    for (int i = 0; i < _countof(args); ++i)
    {
        VariantInit(args + i);
        args[i].vt = VT_BYREF;
    }

    DISPPARAMS dspp;
    ZeroMemory(&dspp, sizeof(dspp));
    dspp.cArgs = _countof(args);
    dspp.rgvarg = args;

    VARIANT ret;
    VariantInit(&ret);

    while (hi > base)
    {
        char *m = (char *)base;
        for (char *it = (char *)base + sizeElem; it <= hi; it += sizeElem)
        {
            args[0].byref = m;
            args[1].byref = it;

            HRESULT hr = p->compare->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dspp, &ret, NULL, NULL);
            if (FAILED(hr)) return hr;

            if (ret.vt != VT_I4)
            {
                VariantClear(&ret);
                return E_FAIL;
            }
            if (ret.lVal > 0) m = it;
            VariantClear(&ret);
        }
        memcpy(temp, m, sizeElem);
        memcpy(m, hi, sizeElem);
        memcpy(hi, temp, sizeElem);
        hi -= sizeElem;
    }

    delete [] temp;
    return S_OK;
}
